package com.kx.center.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import com.kx.center.common.Constant;
import com.kx.center.common.CustomHashMap;

@SuppressWarnings("unchecked")
public class WXUtil {

	/**
	 * 微支付需要的post请求
	 * 
	 * @param url
	 * @param data
	 * @return
	 * @throws HttpException
	 * @throws IOException
	 */
	public static String post(String url, String data) throws HttpException,
			IOException {

		HttpClient httpclient = new HttpClient();
		PostMethod method = new PostMethod(url);

		StringRequestEntity requestEntity = new StringRequestEntity(data,
				"text/xml", "UTF-8");
		method.setRequestEntity(requestEntity);

		int code = httpclient.executeMethod(method);

		byte[] responseBody = null;

		if (code == HttpStatus.SC_OK) {
			Header contentEncoding = method
					.getResponseHeader("Content-Encoding");
			if (contentEncoding != null
					&& contentEncoding.getValue().toLowerCase().indexOf("gzip") > -1) {
				InputStream is = method.getResponseBodyAsStream();
				GZIPInputStream gzip = new GZIPInputStream(is);
				byte[] buf = new byte[1024];

				int num = -1;
				ByteArrayOutputStream baos = new ByteArrayOutputStream();

				while ((num = gzip.read(buf, 0, buf.length)) != -1) {
					baos.write(buf, 0, num);
				}
				responseBody = baos.toByteArray();
				baos.flush();
				baos.close();
				gzip.close();
				is.close();
			} else {
				responseBody = method.getResponseBody();
			}

			Header contentType = method.getResponseHeader("Content-Type");
			if (contentType != null) {
				String encoding = contentType.getValue().toUpperCase();

				Pattern pattern = Pattern.compile("CHARSET=([^;]*)");
				Matcher matcher = pattern.matcher(encoding);
				String charset = matcher.find() ? matcher.group(1) : null;

				if (charset != null) {
					responseBody = (new String(responseBody, charset))
							.getBytes("UTF-8");
				}
			}
		}
		String result = new String(responseBody);
		return result;
	}

	/**
	 * 将map里的参数排序并拼接
	 * @param params
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String concatParams(Map<String, String> params)
			throws UnsupportedEncodingException {
		Object[] key_arr = params.keySet().toArray();
		Arrays.sort(key_arr);
		String str = "";

		for (Object key : key_arr) {
			String val = params.get(key);
			str += "&" + key + "=" + val;
		}

		return str.replaceFirst("&", "");
	}

	/**
	 * xml转map
	 * @param xml
	 * @return
	 * @throws DocumentException
	 */
	@SuppressWarnings("rawtypes")
	public static HashMap<String, Object> xmlToMap(String xml)
			throws DocumentException {

		HashMap<String, Object> map = new HashMap<String, Object>();

		InputSource in = new InputSource(new StringReader(xml));
		in.setEncoding("UTF-8");
		SAXReader reader = new SAXReader();
		Document document = reader.read(in);
		Element root = document.getRootElement();

		Iterator eleIt = root.elementIterator();
		while (eleIt.hasNext()) {
			Element e = (Element) eleIt.next();
			map.put(e.getName(), e.getText());
		}

		return map;
	}

	/**
	 * map转xml
	 * @param vo
	 * @param rootElement
	 * @return
	 */
	public static String mapToXml(Map<String, String> vo, String rootElement) {
		org.dom4j.Document doc = DocumentHelper.createDocument();
		Element body = DocumentHelper.createElement(rootElement);
		doc.add(body);
		__buildMap2xmlBody(body, vo);
		return doc.asXML();
	}

	private static void __buildMap2xmlBody(Element body, Map<String, String> vo) {
		if (vo != null) {
			Iterator<String> it = vo.keySet().iterator();
			while (it.hasNext()) {
				String key = (String) it.next();
				if (StringUtils.isNotEmpty(key)) {
					Object obj = vo.get(key);
					Element element = DocumentHelper.createElement(key);
					if (obj != null) {
						if (obj instanceof java.lang.String) {
							element.setText((String) obj);
						} else {
							if (obj instanceof java.lang.Character
									|| obj instanceof java.lang.Boolean
									|| obj instanceof java.lang.Number
									|| obj instanceof java.math.BigInteger
									|| obj instanceof java.math.BigDecimal) {
								org.dom4j.Attribute attr = DocumentHelper
										.createAttribute(element, "type", obj
												.getClass().getCanonicalName());
								element.add(attr);
								element.setText(String.valueOf(obj));
							} else if (obj instanceof java.util.Map) {
								org.dom4j.Attribute attr = DocumentHelper
										.createAttribute(element, "type",
												java.util.Map.class
														.getCanonicalName());
								element.add(attr);
								__buildMap2xmlBody(element,
										(Map<String, String>) obj);
							} else {
							}
						}
					}
					body.add(element);
				}
			}
		}
	}

	public static String getRemoteIpAddr(HttpServletRequest request) {
		
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	public static boolean checkSign(HashMap<String, Object> data) throws UnsupportedEncodingException{
		
		boolean result = false;
		
        Map<String, String> params = new HashMap<String, String>();

        if (data == null || data.size() <= 0) {
            return result;
        }

        for (String key : data.keySet()) {
            String value = (String) data.get(key);
            if (value == null || value.equals("")) {
                continue;
            }
            params.put(key, value);
        }

		String sign = params.get("sign");
		params.remove("sign");
		
		String content = WXUtil.concatParams(params) + "&key=" + Constant.key_wx + "";
		if(MD5Coder.encode(content).toUpperCase().equals(sign)){
			return true;
		}
		return result;
	}
	
	public static void main(String[] args) throws HttpException, IOException,
			DocumentException {

		HashMap<String, String> map = new HashMap<String, String>();

		map.put("appid", Constant.appid_wx);
		map.put("mch_id", Constant.mch_id_wx);
		map.put("nonce_str", SerialNumber.getRandomString(16));
		map.put("body", "李子园");
		map.put("attach", "259");
		map.put("out_trade_no", "PNoojdbu33hadg");
		map.put("total_fee", "1");
		map.put("spbill_create_ip", "10.12.14.2");
		map.put("notify_url", Constant.WEB_MANAGER_URL + "/api/shopOrder/payment/wzfPush");
		map.put("trade_type", "APP");
		
		String params = WXUtil.concatParams(map) + "&key=" + Constant.key_wx + "";
		String sign = MD5Coder.encode(params).toUpperCase();
		
		map.put("sign", sign);
		
		String xml = WXUtil.mapToXml(map, "xml");
		map.clear();
		String result = WXUtil.post(Constant.pay_url_wx, xml);
		HashMap<String, Object> maps = WXUtil.xmlToMap(result);
		CustomHashMap<String, Object> item = CustomHashMap.convert(maps);
		
		System.out.println(item.getString("prepay_id"));
	}

}
